package com.wing.tools;

import android.media.MediaCodec;
import android.util.Log;

import com.renovavision.videocodec.encoder.TextureEncoder;
import com.wing.tools.rtsp.RtspServer;
import com.wing.tools.video.ZLMediaKit;

import java.io.BufferedOutputStream;
import java.nio.ByteBuffer;

/**
 * Created by wejust on 2017/12/21.
 */

public class ScreenCapturer {
    static {
        System.loadLibrary("zlmediakit");
    }

    long mediacontext;

    TextureEncoder mEncoder;
    int mPort = 5554;
    int mTextureID;
    int mFrameInterval = 2;
    int mOutputWidth = 640,mOutputHeight = 480;
    int mVideoBitrate = 1 * 100 * 1000;
    int mFPS = 10;

    public static ScreenCapturer Create(int texID){
        return new ScreenCapturer(texID);
    }

    public ScreenCapturer(int texID)
    {
        this.mTextureID = texID;
    }

    public void config(int port, int width, int height, int frameInterval, int videoBitrate, int fps)
    {
        this.mPort = port;
        this.mOutputWidth = width;
        this.mOutputHeight = height;
        this.mFrameInterval = frameInterval;
        this.mVideoBitrate = videoBitrate;
        this.mFPS = fps;
    }

    public void start(int port)
    {
        this.mPort = port;

        mEncoder = new MyEncoder();
        ZLMediaKit.initRtspServer((short)mPort);
        mediacontext = ZLMediaKit.createMedia("app", "media");
        ZLMediaKit.mediaInitVideo(mediacontext, mOutputWidth, mOutputHeight, mVideoBitrate);

        mEncoder.start();
        mEncoder.config(mFrameInterval, mVideoBitrate, mOutputWidth, mOutputHeight, mFPS);
    }

    public void stop()
    {
        mEncoder.stop();
        ZLMediaKit.releaseMedia(mediacontext);
    }

    class MyEncoder extends TextureEncoder {

        byte[] mBuffer = new byte[0];
        byte[] mConfig;

        long timer = -1;
        long startTime = 0;

        public BufferedOutputStream outputStream;

        public MyEncoder() {
            super(mTextureID, mOutputWidth, mOutputHeight);
        }

        @Override
        protected void onEncodedSample(MediaCodec.BufferInfo info, ByteBuffer data) {
            // Here we could have just used ByteBuffer, but in real life case we might need to
            // send sample over network, etc. This requires byte[]
            if (mBuffer.length < info.size) {
                mBuffer = new byte[info.size];
            }
            data.position(info.offset);
            data.limit(info.offset + info.size);
            data.get(mBuffer, 0, info.size);

            Log.d("ENCODER_FLAG", String.valueOf(info.flags));

            if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
                // this is the first and only config sample, which contains information about codec
                // like H.264, that let's configure the decoder

                mConfig = new byte[mBuffer.length];
                System.arraycopy(mBuffer, 0, mConfig, 0, mBuffer.length);

            } else {
                boolean iskey = (info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) == MediaCodec.BUFFER_FLAG_KEY_FRAME;

                byte[] dt = mBuffer;
                if (timer < 0 || timer > mFrameInterval * 1000 || iskey) {

                    int nalu_len = 0;
//                    if(mBuffer[0] == 0 && mBuffer[1] ==0 && mBuffer[2] == 0 && mBuffer[3] == 1){
//                        nalu_len = 5;
//                    }
                    byte[] keyframe = new byte[mBuffer.length + mConfig.length - nalu_len];
                    System.arraycopy(mConfig, 0, keyframe, 0, mConfig.length);
                    System.arraycopy(mBuffer, nalu_len, keyframe, mConfig.length, mBuffer.length - nalu_len);

                    dt = keyframe;

                    timer = 0;
                    startTime = System.nanoTime() / 1000000L;
                } else if ((info.flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) {
                    timer += (System.nanoTime() / 1000000L - startTime);
                    //Log.d("dt__", "time:" + timer);
                }

                ZLMediaKit.mediaInputH264(mediacontext, dt, dt.length, System.nanoTime() / 1000000L, true);
            }
        }
    }
}
